/*
 * @Author: your name
 * @Date: 2021-06-07 21:38:11
 * @LastEditTime: 2022-02-20 13:39:43
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edit
 * @FilePath: \telescope1080P\src\display_tips.cpp
 */
#include "display_tips.h"
#include "common.h"
#include "gui_engine.h"
#include "xlog.h"
#include <iostream>
#include <thread>
TipsMsg::TipsMsg()
{
    keepTime = 2000; //默认显示2s
    type = ConfirmationType::TYPE_TIPS;
}
void DisplayTipsPage(TipsMsg initTips, bool immediately)
{
    DisplayTips::GetInstance().OpenDisplayTipsPage(initTips, immediately);
}
void DisplayTips::Display(TipsMsg tips, bool immediately)
{
    // int ret = 0;
    std::thread t(DisplayTipsPage, tips, immediately);
    t.detach(); //设置线程分离属性，线程结束后自动释放资源
}
void DisplayTips::AddTips(TipsMsg tips)
{
    std::lock_guard<std::mutex> locker(m_mutex);
    tipsQueue.push_back(tips);
}
void OpenDisplayTipsPageIQ(void* ctx)
{
    IS_VALID_PTR(ctx)
    Context* p = (Context*)ctx;
    PageHandle* window = new PageHandle;
    if (!window->PageOpen(DISPALY_TIPS_PAGE_NAME)) {
        LOG_E("window open error\n");
        delete window;
        delete p;
        return;
    }
    /**
     * @brief
     * 此处立即显示内容，避免界面空洞。
     */
    TipsMsg tips;
    if (DisplayTips::GetInstance().GetOneTips(tips)) {
        DisplayTips::GetInstance().AddTips(tips);
        Context* p2 = new Context;
        window->SaveContext(p2);
        /**
         * @brief
         * ctx 将会异步释放
         */
        TipsMsg* ctx = new TipsMsg;
        *ctx = tips;
        p2->ctx = ctx;
        DisplayTips::GetInstance().TipsDisplayingSetText(p2);
    }
    window->SaveContext(p);
    DisplayTips::GetInstance().SetPage(window);
}
void TipsDisplayingIQ(void* ctx)
{
    DisplayTips::GetInstance().TipsDisplayingSetText(ctx);
}
void StopDisplayingIQ(void* ctx)
{
    DisplayTips::GetInstance().StopDisplayingClosePage();
}
void TipsDisplayingThread()
{
    DisplayTips::GetInstance().TipsDisplaying();
}
DisplayTips::DisplayTips()
{
    keepTime = 2000;
    keepWorking = false;
}
DisplayTips& DisplayTips::GetInstance()
{
    static DisplayTips displayTips;
    return displayTips;
}
void DisplayTips::OpenDisplayTipsPage(TipsMsg initTips, bool immediately)
{
    static std::mutex lock;
    std::unique_lock<std::mutex> mtx_lock(lock, std::defer_lock);
    if (mtx_lock.try_lock() == true) {
        AddTips(initTips);
        keepWorking = true;
        Context* p = new Context;
        p->eventCallback = OpenDisplayTipsPageIQ;
        if (!GuiEngine::GetInstance().IdleQueue(p)) {
            LOG_W("IdleQueue_V2 falied\n");
            delete p;
        }
        std::thread t(TipsDisplayingThread);
        t.join();
        StopDisplay();
        mtx_lock.unlock();
    } else {
        if (immediately) {
            TipsDisplayingRightNow(initTips);
        } else {
            AddTips(initTips);
        }
        LOG_I("display tips page has been opened\n");
    }
}
void DisplayTips::SetPage(PageHandle* window)
{
    std::lock_guard<std::mutex> locker(m_mutex);
    page.reset(window);
}
bool DisplayTips::GetOneTips(TipsMsg& tips)
{
    std::lock_guard<std::mutex> locker(m_mutex);
    if (tipsQueue.size() == 0) {
        return false;
    }
    tips = tipsQueue.front();
    tipsQueue.pop_front();
    return true;
}
PageHandle* DisplayTips::GetPage()
{
    std::lock_guard<std::mutex> locker(m_mutex);
    return page.get();
}
void DisplayTips::TipsDisplaying()
{
    TipsMsg tips;
    unsigned int SLEEP = 300;
    while (keepWorking) {
        if (!GetPage()) {
            LOG_W("display tips page isn't opened,waiting...\n");
            std::this_thread::sleep_for(std::chrono::milliseconds(200));
            continue;
        }
        if (GetOneTips(tips)) {
            LOG_I(" show tips = %s\n", tips.GetTips().c_str());
            Context* p = new Context;
            p->eventCallback = TipsDisplayingIQ;
            /**
             * @brief
             * ctx 将会异步释放
             */
            TipsMsg* ctx = new TipsMsg;
            *ctx = tips;
            p->ctx = ctx;
            keepTime = tips.GetKeepTime();
            if (!GuiEngine::GetInstance().IdleQueue(p)) {
                LOG_W("IdleQueue_V2 falied\n");
                delete p;
            } else {
                GetPage()->SaveContext(p);
            }
            sleepTime = 0;
            while (keepWorking) {
                std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP));
                sleepTime += SLEEP;
                if (sleepTime >= keepTime) {
                    break;
                }
            }
        } else {
            break;
        }
    }
}
void DisplayTips::StopDisplay()
{
    Context* p = new Context;
    p->eventCallback = StopDisplayingIQ;
    if (!GuiEngine::GetInstance().IdleQueue(p)) {
        LOG_W("IdleQueue_V2 falied\n");
        delete p;
        return;
    }
    GetPage()->SaveContext(p);
}
void DisplayTips::TipsDisplayingSetText(void* ctx)
{
    IS_VALID_PTR(ctx)
    if (page) {
        Widget* windowWidget = page->GetThisPage();
        std::unique_ptr<Widget> labelTips(GuiEngine::GetInstance().NewWidget());
        if (GuiEngine::GetInstance().Lookup(windowWidget, "tipsMsg", true, labelTips.get())) {
            TipsMsg tips;
            Context* p = (Context*)ctx;
            if (p->GetData(tips)) {
                /**
                 * @brief
                 * 优先使用译文显示提示信息。
                 */
                if (tips.GetTrText().size() > 0) {
                    GuiEngine::GetInstance().SetTrText(labelTips.get(), tips.GetTrText().c_str());
                } else {
                    GuiEngine::GetInstance().SetTextUtf8(labelTips.get(), tips.GetTips().c_str());
                }
                if (GuiEngine::GetInstance().Lookup(windowWidget, "title", true, labelTips.get())) {
                    GuiEngine::GetInstance().SetTrText(labelTips.get(), typeTrText[static_cast<int>(tips.GetType())].c_str());
                }
                delete (TipsMsg*)p->ctx;
            } else {
                LOG_E("get no tips msg\n");
            }
        }
    } else {
        LOG_E("display page is nullptr\n");
    }
}
void DisplayTips::StopDisplayingClosePage()
{
    page.get()->PageClose();
}
void DisplayTips::TipsDisplayingRightNow(TipsMsg tips)
{
    Context* p = new Context;
    p->eventCallback = TipsDisplayingIQ;
    /**
     * @brief
     * ctx 将会异步释放
     */
    TipsMsg* ctx = new TipsMsg;
    *ctx = tips;
    p->ctx = ctx;
    sleepTime = 0;
    keepTime = tips.GetKeepTime();
    // return;
    if (!GuiEngine::GetInstance().IdleQueue(p)) {
        LOG_W("IdleQueue_V2 falied\n");
        delete p;
    } else {
        while (!GetPage()) {
            LOG_W("display tips page isn't opened,waiting...\n");
            std::this_thread::sleep_for(std::chrono::milliseconds(200));
            continue;
        }
        GetPage()->SaveContext(p);
    }
}
void DisplayTips::ForceStopDisplay()
{
    keepWorking = false;
}
void DisplayTips::SaveConfiguration(bool ret)
{
    TipsMsg tips;
    if (ret) {
        tips.SetTrText("saveSucceed");
    } else {
        tips.SetTrText("saveFailed");
    }
    DisplayTips::GetInstance().Display(tips);
}

void DisplayTips::DisplayNameNotEmpty()
{
    TipsMsg tips;
    tips.SetTrText("DisplayNameNotEmpty");
    DisplayTips::GetInstance().Display(tips);
}

void DisplayTips::ValueInvalid()
{
    TipsMsg tips;
    tips.SetTrText("ValueInvalid");
    DisplayTips::GetInstance().Display(tips);
}